#pragma once

#include <string>
#include <vector>
#include <functional>
#include <unordered_map>

#include "lib/Log.hpp"
#include "lib/Socket.hpp"
#include "lib/Protocol.hpp"
#include "Epoll.hpp"
#include "threadpool/LockGuard.hpp"

using namespace ns_protocol;

class Connection;
class TcpServer;

using func_t = std::function<void(Connection *)>;
using handler_t = std::function<void(Connection*)>;

class Connection
{
public:
    Connection(int sock, TcpServer *ptr)
        : _sock(sock), _tcpserver_ptr(ptr),
          _recv_callback(nullptr), _send_callback(nullptr), _exception_callback(nullptr)
    {
    }
    // 回调方法的设置
    void SetCallBack(func_t recv_callback, func_t send_callback, func_t exception_callback)
    {
        _recv_callback = recv_callback;
        _send_callback = send_callback;
        _exception_callback = exception_callback;
    }

    ~Connection()
    {
    }

public:
    int _sock;
    // 函数回调
    func_t _recv_callback;
    func_t _send_callback;
    func_t _exception_callback;
    // 缓冲区
    std::string _recv_buffer;
    std::string _send_buffer;
    // 为了多线程设置缓冲区的锁
    Lock _send_write_lock;

    // TcpServer ptr
    TcpServer *_tcpserver_ptr;
};

class TcpServer
{
    const static uint16_t g_port = 8080;
    const static int g_events_num = 56;
    const static int g_timeout = 3000;

public:
    TcpServer()
        : _port(g_port), _events_num(g_events_num), _timeout(g_timeout)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        // _events
        _events = new struct epoll_event[_events_num];
        if (_events == nullptr)
        {
            Messagelog(FATAL, "new events error");
            exit(21);
        }
        // 添加连接给 epoll 和 map
        AddConnection(_listensock, std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
    }
    // 派发
    void Dispather(handler_t handler)
    {
        _handler_cb = handler;
        while (true)
        {
            LoopOnce();
        }
    }

    ~TcpServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if (_events)
            delete[] _events;
        for(auto& it : _connections)
        {
            delete it.second;
        }
    }

    bool EnableReadWrite(Connection* con, bool read, bool write)
    {
        uint32_t event = EPOLLET;
        if(read) event |= EPOLLIN;
        if(write) event |= EPOLLOUT;
        if(!_poll.EpollClt(con->_sock, event))
        {
            Messagelog(ERROR, "EnableReadWrite error %d:%s", errno, strerror(errno));
            return false;
        }
        return true;
    }

private:
    void LoopOnce()
    {
        int n = _poll.EpollWait(_events, _events_num, _timeout);
        // if(n == 0)
        // {
        //     Messagelog(NORMAL, "time out ...");
        // }
        for (int i = 0; i < n; ++i)
        {
            int sock = _events[i].data.fd;
            uint32_t event = _events[i].events;
            if (event & EPOLLIN)
            {
                if (IsConnectionExit(sock) && _connections[sock]->_recv_callback != nullptr)
                    _connections[sock]->_recv_callback(_connections[sock]);// 回调
            }
            if (event & EPOLLOUT)
            {
                if (IsConnectionExit(sock) && _connections[sock]->_send_callback != nullptr)
                    _connections[sock]->_send_callback(_connections[sock]);
            }
        }
    }

    void Accepter(Connection *con)
    {
        // Messagelog(DEBUG, "accept call successful");
        // 建立连接
        while(true)
        {
            std::string cli_ip;
            uint16_t cli_port;
            int sock = Sock::Accept(_listensock, &cli_ip, &cli_port);
            if(sock < 0)
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                else if(errno == EINTR) continue;
                else 
                {
                    Messagelog(ERROR, "connect fail:%d-%s", errno, strerror(errno)); 
                    continue;
                }
            }
            if(sock >= 0)
            {
                AddConnection(sock, std::bind(&TcpServer::Recver, this, std::placeholders::_1), 
                                std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                                std::bind(&TcpServer::Excepter, this, std::placeholders::_1));
            }
        }
    }

    void Recver(Connection *con)
    {
        // Messagelog(NORMAL, "recver success");
        // 读事件就绪
        // 1. 非阻塞读，放到buffer里面
        const int buffer_num = 1024;
        char buffer[buffer_num];
        while(true)
        {
            ssize_t sz = recv(con->_sock, buffer, buffer_num - 1, 0);
            if(sz < 0)
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                    break; // 读完了
                else if(errno == EINTR) continue;
                else 
                {
                    con->_exception_callback(con);
                    return; // 结束
                }
            }
            else if(sz == 0)// client关闭
            {
                Messagelog(NORMAL, "client [%d] quit, me too...", con->_sock);
                // DeleteConnection(con->_sock);
                con->_exception_callback(con);
                return;
            }
            else
            {
                buffer[sz] = 0;
                // std::cout << buffer << ":" << sz << std::endl;
                // if(buffer[sz - 1] == '\n') buffer[sz - 1] = 0;
                // if(sz - 2 >= 0 && buffer[sz - 2] == '\r') buffer[sz - 2] = 0;
                con->_recv_buffer += buffer;
            }
        }
        _handler_cb(con);
    }

    void Sender(Connection *con)
    {
        // Messagelog(NORMAL, "Sender success");
        // 1. 非阻塞发送，
        while(true)
        {
            ssize_t sz = send(con->_sock, con->_send_buffer.c_str(), con->_send_buffer.size(), 0);
            if(sz < 0)
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                {    
                    break; // 没有空间了
                }
                else if(errno == EINTR) continue;
                else 
                {
                    con->_exception_callback(con);
                    return; 
                }
            }
            else// 
            {
                Messagelog(ERROR, "sz:%d", sz);

                con->_send_buffer.erase(0, sz);
                if(con->_send_buffer.empty()) break;
            }
        }
        // 2. 根据发送情况设置，a 发完了 b 对方没有空间了
        if(con->_send_buffer.empty()) EnableReadWrite(con, true, false);
        else EnableReadWrite(con, true, true);
    }
    
    void Excepter(Connection *con)
    {
        Messagelog(NORMAL, "Excepter success");
        DeleteConnection(con->_sock);
    }



///////////////////////////////////////////////////////

    // 添加sock到连接
    void AddConnection(int sock, func_t recv_callback, func_t send_callback, func_t exception_callback)
    {
        // 为了ET模式，必须阻塞式的读
        if (!Sock::NonBlock(sock))
        {
            Messagelog(ERROR, "NonBlock sock: %d error %d:%s", sock, errno, strerror(errno));
            exit(22);
        }
        // a.添加sock到epoll，默认行为 读和ET
        if (!_poll.AddSockToEpoll(sock, EPOLLIN | EPOLLET))
        {
            Messagelog(ERROR, "AddSockToEpoll sock: %d error %d:%s", sock, errno, strerror(errno));
            exit(23);
        }
        // b.添加sock和connection到map
        Connection *con = new Connection(sock, this);
        con->SetCallBack(recv_callback, send_callback, exception_callback);
        _connections.insert(std::make_pair(sock, con));
    }

    // 删除sock连接, 关闭sock文件描述符
    void DeleteConnection(int sock)
    {
        // 问题2.这里因为是多线程，如果client断开，就会回收，但是多线程并不能知道这个情况，还会使用Connection的指针
        // 除了usleep等一会，还有没有其他解决方案
        // 因为等就会导致效率降低，这是在主执行流的情况下等
        usleep(1000); // 这里是多线程情况下，如果突然就释放空间，就会出现野指针问题
        // a.epoll中删除
        if (!_poll.DeleteSockFromEpoll(sock))
        {
            Messagelog(ERROR, "DeleteSockToEpoll sock: %d error %d:%s", sock, errno, strerror(errno));
            exit(24);
        }
        // b.map中删除
        if(!IsConnectionExit(sock))
            Messagelog(ERROR, "DeleteConnection sock: %d error map not exit");
        Connection* rm = _connections[sock];
        _connections.erase(sock);
        delete rm; // 释放空间
        // c.关闭文件描述符
        close(sock);
    }

    bool IsConnectionExit(int sock)
    {
        if (_connections.find(sock) == _connections.end())
            return false;
        return true;
    }

private:
    uint16_t _port;
    int _listensock;
    Epoll _poll;
    // epoll对应参数
    struct epoll_event *_events;
    int _events_num;
    int _timeout;
    // connections 管理，主要是为了记录连接然后方便回调
    std::unordered_map<int, Connection *> _connections;

    handler_t _handler_cb;
};